{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "### 元组的特征\n",
    "1. 有序性：元组是有序的，元素在元组中的位置是固定的，并且可以根据索引进行访问。\n",
    "\n",
    "2. 不可变性：元组是不可变的，一旦创建，就不能修改其元素。这意味着不能添加、删除或修改元组的元素。但是，如果元组的元素是可变对象（如列表），则可以修改可变对象的状态。\n",
    "\n",
    "3. 可混合数据类型：元组可以包含不同类型的元素，包括数字、字符串、列表、元组等。元组中的元素可以是任何有效的Python对象。\n",
    "\n",
    "4. 使用圆括号：元组使用圆括号 () 来定义，并且元素之间使用逗号 , 分隔。例如，(1, 2, 3) 是一个包含三个整数的元组。\n",
    "\n",
    "5. 索引和切片：可以使用索引和切片操作来访问元组中的元素。索引从0开始，可以使用负数索引从末尾开始访问元素。切片操作可以提取元组的子集。\n",
    "\n",
    "6. 不可变性的优点：由于元组是不可变的，它们在一些特定场景下很有用，例如作为字典的键、作为函数的参数传递和保护数据不被意外修改。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "### 创建元组\n",
    "可以使用圆括号 () 来创建一个元组，并在其中放置元素，用逗号 , 分隔。如果元组只包含一个元素，需要在元素后面添加一个逗号，以区分元组和普通括号内的表达式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T08:38:14.020964900Z",
     "start_time": "2024-02-24T08:38:14.016962500Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "my_tuple = (1, 2, 3)  # 包含三个整数的元组\n",
    "single_tuple = (4,)  # 包含一个整数的元组"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "### 解包元组\n",
    "* 可以将元组的元素解包到变量中，以便单独访问每个元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T08:38:52.017216700Z",
     "start_time": "2024-02-24T08:38:52.006223300Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3\n",
      "a:1, b:2, c:3\n"
     ]
    }
   ],
   "source": [
    "my_tuple = (1, 2, 3)\n",
    "a, b, c = my_tuple  # 解包元组\n",
    "print(a, b, c)  # 输出: 1 2 3\n",
    "\n",
    "print('a:%s, b:%s, c:%s' % my_tuple)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "* 用 * 运算符把一个可迭代对象拆开作为函数的参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T09:18:03.931148400Z",
     "start_time": "2024-02-24T09:18:03.922639Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "参数数量：1, 参数值：(('a', 'b', 'c'),)\n",
      "参数数量：3, 参数值：('a', 'b', 'c')\n"
     ]
    }
   ],
   "source": [
    "def get_args_num(*args):\n",
    "    num_args = len(args)\n",
    "    print(r\"参数数量：{}, 参数值：{}\".format(num_args, args) )\n",
    "\n",
    "args_tuple=('a','b','c')\n",
    "get_args_num(args_tuple) # 参数数量：1, 参数值：(('a', 'b', 'c'),)\n",
    "get_args_num(*args_tuple) # 参数数量：3, 参数值：('a', 'b', 'c')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "* 用*来处理剩下的元素"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T09:47:58.181869500Z",
     "start_time": "2024-02-24T09:47:58.179870700Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 1 [2, 3, 4]\n",
      "0 1 [2]\n",
      "0 1 []\n",
      "0 [1, 2, 3, 4] 5\n",
      "[0, 1, 2] 3 4\n"
     ]
    }
   ],
   "source": [
    "a,b,*rest = range(5)\n",
    "print(a, b, rest)\n",
    "a,b,*rest = range(3)\n",
    "print(a, b, rest)\n",
    "a,b,*rest = range(2)\n",
    "print(a, b, rest)\n",
    "a,*rest,b = range(6)\n",
    "print(a, rest, b)\n",
    "*rest,a,b = range(5)\n",
    "print(rest, a, b)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "### 元组方法\n",
    "元组是不可变对象，因此没有提供用于修改元组的方法。但是，元组提供了一些方法用于查询和操作元组的内容，如 count() 和 index()。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T08:39:32.346528200Z",
     "start_time": "2024-02-24T08:39:32.324434500Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [],
   "source": [
    "my_tuple = (1, 2, 2, 3, 3, 3)\n",
    "count_2 = my_tuple.count(2)  # 统计元素 2 的出现次数\n",
    "index_3 = my_tuple.index(3)  # 获取元素 3 的索引位置"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "### 元组与列表的比较\n",
    "元组和列表都是序列类型，但它们之间有一个重要的区别：元组是不可变的，列表是可变的。如果需要对序列进行增删改操作，应该使用列表。而如果需要创建一个不可变的、保持数据不变性的序列，可以选择元组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T09:21:12.985462300Z",
     "start_time": "2024-02-24T09:21:12.828553100Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('/home/luciano/.ssh', 'idrsa.pub')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os\n",
    "_, filename = os.path.split('/home/luciano/.ssh/idrsa.pub')\n",
    "_, filename"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "### 具名元组\n",
    "collections.namedtuple 是一个工厂函数， 用于创建具有命名字段的元组子类。它提供了一种方便的方式来定义简单的数据对象，其中每个字段都有一个名称，使得代码更易读和维护。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T09:57:31.414938200Z",
     "start_time": "2024-02-24T09:57:31.409935400Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Person(name='Alice', age=25, city='New York')\n",
      "Alice 25 New York\n"
     ]
    }
   ],
   "source": [
    "import collections\n",
    "\n",
    "Person = collections.namedtuple('Person', ['name', 'age', 'city'])\n",
    "# 可以通过两种方式创建命名元组的实例： 按顺序传递字段的值，或者使用关键字参数传递字段的值\n",
    "\n",
    "person1 = Person('Alice', 25, 'New York') # 按顺序传递字段的值\n",
    "\n",
    "person2 = Person(name='Bob', age=30, city='London') # 使用关键字参数传递字段的值\n",
    "\n",
    "print(person1)\n",
    "print(person1.name, person1.age, person1.city)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "#### 不可变性和字段顺序\n",
    "\n",
    "命名元组实例是不可变的，无法修改其字段的值。并且它们的字段顺序是固定的，与定义时的顺序一致。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T10:00:44.921048100Z",
     "start_time": "2024-02-24T10:00:44.911281900Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "can't set attribute",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mAttributeError\u001B[0m                            Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[23], line 1\u001B[0m\n\u001B[1;32m----> 1\u001B[0m \u001B[43mperson1\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mage\u001B[49m \u001B[38;5;241m=\u001B[39m \u001B[38;5;241m26\u001B[39m  \u001B[38;5;66;03m# 这将引发 AttributeError，命名元组实例是不可变的\u001B[39;00m\n",
      "\u001B[1;31mAttributeError\u001B[0m: can't set attribute"
     ]
    }
   ],
   "source": [
    "person1.age = 26  # 这将引发 AttributeError，命名元组实例是不可变的"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "source": [
    "#### 其他方法和属性\n",
    "* _fields：包含命名元组字段名称的元组。\n",
    "* _make(iterable)：从可迭代对象创建命名元组实例。\n",
    "* _asdict()：将命名元组转换为有序字典。\n",
    "* _replace(**kwargs)：创建一个新的命名元组实例，并用提供的关键字参数替换字段的值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-02-24T10:02:49.150033Z",
     "start_time": "2024-02-24T10:02:49.122051100Z"
    },
    "collapsed": false,
    "jupyter": {
     "outputs_hidden": false
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('name', 'age', 'city')\n",
      "Person(name='Charlie', age=35, city='Paris')\n",
      "{'name': 'Bob', 'age': 30, 'city': 'London'}\n",
      "Person(name='Charlie', age=36, city='Paris')\n"
     ]
    }
   ],
   "source": [
    "print(person1._fields)  # 输出: ('name', 'age', 'city')\n",
    "person3 = Person._make(['Charlie', 35, 'Paris'])\n",
    "print(person3)  # 输出: Person(name='Charlie', age=35, city='Paris')\n",
    "person_dict = person2._asdict()\n",
    "print(person_dict)  # 输出: {'name': 'Bob', 'age': 30, 'city': 'London'}\n",
    "person4 = person3._replace(age=36)\n",
    "print(person4)  # 输出: Person(name='Charlie', age=36, city='Paris')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
